'''
Created on 2010-2-12

@author: summit
'''
import sys
from Object import *
from Visitor import *

class Container(Object):
    '''
    A container may be empty or it may contain one or more other 
    objects.Typically, a container has finite capacity. So, a 
    single instance attribute called _count is used to keep track
    of the number of object held in the container.
    '''
    _count = 0

    def __init__(self):
        '''
        Constructor
        '''
        super(Container, self).__init__()

    def purge(self):
        '''
        The purpose of the purge method is to discard all of content
        of a container. After a container is purged, the value of 
        _count instance attribute should be zero
        '''
        pass
    
    purge = AbstractMethod(purge)
    
    def accept(self, visitor):
        '''
        the accept method of the Container class takes as its argument a any object
        that is an instance of a class derived from the Visitor class
        '''
        assert isinstance(visitor, Visitor)
        for obj in self:
            visitor.visit(obj)
    
    def __iter__(self):
        '''
        The purpose of the __iter__ method is to return an iterator
        that enumerates the objects in the container.
        '''
        pass
    
    __iter__ = AbstractMethod(__iter__)
    
    def getCount(self):
        return self._count
    
    # Notice that the properties are implemented as lambda expressions.
    # The reson for this is that when a Python property is created it
    # is bound to a specific method instance. The problem with this is
    # that if a property is bound to a specific method in a base class,
    # and a derived method overrides the method, the property still 
    # remains bound to the original base class method. Thus, we would
    # have to also override the property in the derived class in order
    # to get the desired behavior. By binding the property to a lambda
    # function that calls the desired method, when the method is 
    # overridden in a derived class, the property need not also be overridden
    # in that derived class. 
    count = property(fget=lambda self: self.getCount())
    
    def getIsEmpty(self):
        '''
        bool-valued methods which indicate whether a given container
        is empty or full.Notice that the getIsEmpty get accessor does
        not directly access the count instance attribute. Instead it
        uses Count property.
        '''
        return self.count == 0
    
    isEmpty = property(fget=lambda self: self.getIsEmpty())
    
    def getIsFull(self):
        '''
        bool-valued methods which indicate whether a given container
        is empty or full
        '''
        return False
    
    isFull = property(fget=lambda self: self.getIsFull())
    
    class StrVisitor(Visitor):
        
        def __init__(self):
            self._string = ""
            self._comma = False
        
        def visit(self, object):
            if self._comma:
                self._string = self._string + ", "
            self._string = self._string + str(object)
            self._comma = True
        
        def __str__(self):
            return self._string
    
    def __str__(self):
        visitor = Container.StrVisitor()
        self.accept(visitor)
        return "%s {%s}" % (self.__class__.__name__, str(visitor))
    
    def __hash__(self):
        result=hash(self.__class__)
        for obj in self:
            result=(result+hash(obj))&sys.maxint
        return result
    
    @staticmethod
    def main(*argv):
        "Container test program."
        print Container.main.__doc__

        class Dummy(Container):
            def _compareTo(self, obj): pass
            def purge(self): pass
            def __iter__(self): pass
        container = Dummy()
        print container._count
        return 0

if __name__ == "__main__":
    sys.exit(Container.main(*sys.argv))